﻿using System;
using System.ComponentModel;
using System.Configuration;
using System.Drawing;
using System.Drawing.Design;
using System.Windows.Forms;
using System.Diagnostics;

namespace Kyoh.Lib.WinForms
{
    /// <summary>フォームの拡張クラスです。</summary>
    public partial class FormPlus : Form
    {
        private readonly FormPlusSettings _settings;

        /// <summary><see cref="FormPlus"/> クラスの新しいインスタンスを初期化します。</summary>
        public FormPlus()
            : this(null)
        {
        }

        /// <summary><see cref="FormPlus"/> クラスの新しいインスタンスを初期化します。</summary>
        /// <param name="settings">フォームの設定値を保存する <see cref="ApplicationSettingsBase"/>。</param>
        public FormPlus(SettingsBase settings)
        {
            Debug.WriteLine("FormPlus::Constructing" + DateTime.Now);
            _sizeInitialized = false;
            InitializeComponent();
            _settings = new FormPlusSettings(settings);
            Debug.WriteLine("FormPlus::Constructed" + DateTime.Now);
        }
        
        #region 通知アイコン
        /// <summary>フォームのアイコンを取得または設定します。</summary>
        [Localizable(true)]
        [AmbientValue("")]
        public new Icon Icon { get { return base.Icon; } set { base.Icon = notifyIcon1.Icon = value; } }
        /// <summary>フォームのキャプション バーにアイコンを表示するかどうかを示す値を取得または設定します。</summary>
        [DefaultValue(true)]
        public new bool ShowIcon { get { return base.ShowIcon; } set { base.ShowIcon = notifyIcon1.Visible = value; } }
        /// <summary>フォームのキャプション バーに表示するテキスト。</summary>
        [SettingsBindable(true)]
        public override string Text { get { return base.Text; } set { base.Text = notifyIcon1.Text = value; } }
        /// <summary><see cref="NotifyIcon"/> に関連付けられているバルーン ヒントに表示するアイコンを取得または設定します。</summary>
        /// <exception cref="System.ComponentModel.InvalidEnumArgumentException">指定された値が <see cref="ToolTipIcon"/> ではありません。</exception>
        public ToolTipIcon BalloonTipIcon { get { return notifyIcon1.BalloonTipIcon; } set { notifyIcon1.BalloonTipIcon = value; } }
        /// <summary><see cref="NotifyIcon"/> に関連付けられているバルーン ヒントに表示するテキストを取得または設定します。</summary>
        [DefaultValue("")]
        [Editor("System.ComponentModel.Design.MultilineStringEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]
        [Localizable(true)]
        public string BalloonTipText { get { return notifyIcon1.BalloonTipText; } set { notifyIcon1.BalloonTipText = value; } }
        /// <summary><see cref="NotifyIcon"/> で表示されるバルーン ヒントのタイトルを取得または設定します。</summary>
        [Localizable(true)]
        [DefaultValue("")]
        public string BalloonTipTitle { get { return notifyIcon1.BalloonTipTitle; } set { notifyIcon1.BalloonTipTitle = value; } }
        /// <summary><see cref="NotifyIcon"/> に関連付けられたショートカット メニューを取得または設定します。</summary>
        [DefaultValue("")]
        public ContextMenuStrip NotifyContextMenuStrip { get { return notifyIcon1.ContextMenuStrip; } set { notifyIcon1.ContextMenuStrip = value; } }
        /// <summary>バルーン ヒントがクリックされたときに発生します。</summary>
        public event EventHandler BalloonTipClicked { add { notifyIcon1.BalloonTipClicked += value; } remove { notifyIcon1.BalloonTipClicked -= value; } }
        /// <summary>ユーザーがバルーン ヒントを閉じたときに発生します。</summary>
        public event EventHandler BalloonTipClosed { add { notifyIcon1.BalloonTipClosed += value; } remove { notifyIcon1.BalloonTipClosed -= value; } }
        /// <summary>画面にバルーン ヒントが表示されたときに発生します。</summary>
        public event EventHandler BalloonTipShown { add { notifyIcon1.BalloonTipShown += value; } remove { notifyIcon1.BalloonTipShown -= value; } }
        /// <summary>通知領域のアイコンをクリックすると発生します。</summary>
        public event EventHandler NotifyIconClick { add { notifyIcon1.Click += value; } remove { notifyIcon1.Click -= value; } }
        /// <summary>タスクバーの通知領域のアイコンをダブルクリックすると発生します。</summary>
        public event EventHandler NotifyIconDoubleClick { add { notifyIcon1.DoubleClick += value; } remove { notifyIcon1.DoubleClick -= value; } }
        /// <summary>ユーザーがマウスで System.Windows.Forms.NotifyIcon をクリックすると発生します。</summary>
        public event MouseEventHandler NotifyIconMouseClick { add { notifyIcon1.MouseClick += value; } remove { notifyIcon1.MouseClick -= value; } }
        /// <summary>ユーザーがマウスで System.Windows.Forms.NotifyIcon をダブルクリックすると発生します。</summary>
        public event MouseEventHandler NotifyIconMouseDoubleClick { add { notifyIcon1.MouseDoubleClick += value; } remove { notifyIcon1.MouseDoubleClick -= value; } }
        /// <summary>ポインタがタスクバーの通知領域のアイコンの上にあるときに、マウス ボタンを押すと発生します。</summary>
        public event MouseEventHandler NotifyIconMouseDown { add { notifyIcon1.MouseDown += value; } remove { notifyIcon1.MouseDown -= value; } }
        /// <summary>ポインタがタスクバーの通知領域のアイコンの上にあるときに、マウスを移動すると発生します。</summary>
        public event MouseEventHandler NotifyIconMouseMove { add { notifyIcon1.MouseMove += value; } remove { notifyIcon1.MouseMove -= value; } }
        /// <summary>ポインタがタスクバーの通知領域のアイコンの上にあるときに、マウス ボタンを離すと発生します。</summary>
        public event MouseEventHandler NotifyIconMouseUp { add { notifyIcon1.MouseUp += value; } remove { notifyIcon1.MouseUp -= value; } }
        /// <summary>タスクバーにバルーン ヒントを指定された時間だけ表示します。</summary>
        /// <param name="timeout">バルーン ヒントを表示する時間 (ミリ秒単位)。</param>
        /// <exception cref="System.ArgumentOutOfRangeException"><paramref name="timeout"/> が 0 未満です。</exception>
        public void ShowBalloonTip(int timeout) { notifyIcon1.ShowBalloonTip(timeout); }
        /// <summary>指定したタイトル、テキスト、アイコンを含むバルーン ヒントを、指定した時間だけタスクバーに表示します。</summary>
        /// <param name="timeout">バルーン ヒントを表示する時間 (ミリ秒単位)。</param>
        /// <param name="tipTitle">バルーン ヒントに表示するタイトル。</param>
        /// <param name="tipText">バルーン ヒントに表示するテキスト。</param>
        /// <param name="tipIcon"><see cref="ToolTipIcon"/> 値の 1 つ。</param>
        /// <exception cref="System.ArgumentOutOfRangeException"><paramref name="timeout"/> が 0 未満です。</exception>
        /// <exception cref="System.ArgumentException"><paramref name="tipText"/> は、<c>null</c> または空の文字列です。</exception>
        /// <exception cref="System.ComponentModel.InvalidEnumArgumentException"><paramref name="tipIcon"/> が <see cref="ToolTipIcon"/> のメンバではありません。</exception>
        public void ShowBalloonTip(int timeout, string tipTitle, string tipText, ToolTipIcon tipIcon) { notifyIcon1.ShowBalloonTip(timeout, tipTitle, tipText, tipIcon); }
        #endregion

        #region ウインドウ状態の変更・復帰

        /// <summary>
        /// <see cref="E:System.Windows.Forms.Form.Load"/> イベントを発生させます。
        /// </summary>
        /// <param name="e">イベント データを格納している <see cref="T:System.EventArgs"/>。</param>
        protected override void OnLoad(EventArgs e)
        {
            if (DesignMode)
            {
                base.OnLoad(e);
                return;
            }
            // ウィンドウサイズと状態の復帰
            if (_settings.SettingsMemorizeWindowSize)
                LoadWindowSize();
            lock (WindowStateLocker)
                _sizeInitialized = true;
            base.OnLoad(e);
        }

        /// <summary>
        /// <see cref="E:System.Windows.Forms.Form.FormClosing"/> イベントを発生させます。
        /// </summary>
        /// <param name="e">イベント データを格納している <see cref="T:System.Windows.Forms.FormClosingEventArgs"/>。</param>
        protected override void OnFormClosing(FormClosingEventArgs e)
        {
            if (!DesignMode)
                CloseToMinimize(e);
            base.OnFormClosing(e);
        }

        /// <summary>
        /// <see cref="E:System.Windows.Forms.Form.ResizeBegin"/> イベントを発生させます。
        /// </summary>
        /// <param name="e">イベント データを格納している <see cref="T:System.EventArgs"/>。</param>
        protected override void OnResizeBegin(EventArgs e)
        {
            if (!DesignMode)
                SaveWindowSize();
            base.OnResizeBegin(e);
        }

        /// <summary>
        /// <see cref="E:System.Windows.Forms.Form.ResizeEnd"/> イベントを発生させます。
        /// </summary>
        /// <param name="e">イベント データを格納している <see cref="T:System.EventArgs"/>。</param>
        protected override void OnResizeEnd(EventArgs e)
        {
            if (!DesignMode)
                SaveWindowSize();
            base.OnResizeEnd(e);
        }

        /// <param name="e">イベント データを格納している <see cref="T:System.EventArgs"/>。</param>
        protected override void OnResize(EventArgs e)
        {
            if (!DesignMode)
            {
                SaveWindowSize();
                MinimizeToNotifier();
            }
            base.OnResize(e);
        }

        private bool _sizeInitialized;

        /// <summary>アプリケーションを終了します。</summary>
        protected virtual void Exit()
        {
            Application.Exit();
        }

        /// <summary><see cref="Size"/> を設定値に保存します。</summary>
        protected virtual void SaveWindowSize()
        {
            if (DesignMode)
                return;
            lock (WindowStateLocker)
            {
                if (!_sizeInitialized)
                    return;
                switch (WindowState)
                {
                    case FormWindowState.Normal:
                        _settings.SettingsWindowSize = Size;
                        _settings.SettingsWindowState = WindowState;
                        break;
                    case FormWindowState.Maximized:
                        _settings.SettingsWindowState = WindowState;
                        break;
                }
            }
        }

        /// <summary><see cref="Size"/> を設定値に基づく値に設定します。</summary>
        protected virtual void LoadWindowSize()
        {
            if (DesignMode)
                return;
            lock (WindowStateLocker)
            {
                Size = _settings.SettingsWindowSize;
                WindowState = _settings.SettingsWindowState;
            }
        }

        /// <summary>フォームを閉じる代わりに、設定に従った動作を実行します。</summary>
        /// <param name="e"><see cref="OnFormClosing"/> メソッドに渡される <see cref="FormClosingEventArgs"/>。</param>
        protected virtual void CloseToMinimize(FormClosingEventArgs e)
        {
            if (DesignMode)
                return;
            if (e.CloseReason == CloseReason.UserClosing)
            {
                var always = _settings.SettingsFormClosingBehavior;
                switch (always)
                {
                    case FormClosingBehavior.Minimize:
                        WindowState = FormWindowState.Minimized;
                        e.Cancel = true;
                        break;
                    case FormClosingBehavior.ConfirmToQuit:
                        DialogResult confirm;
                        bool memory;
                        using (var dialog = new ClosingDialog())
                        {
                            confirm = dialog.ShowDialog(this);
                            memory = dialog.Memory;
                        }
                        switch (confirm)
                        {
                            case DialogResult.Yes:
                                WindowState = FormWindowState.Minimized;
                                e.Cancel = true;
                                always = FormClosingBehavior.Minimize;
                                break;
                            case DialogResult.No:
                                notifyIcon1.Visible = false;
                                always = FormClosingBehavior.Quit;
                                break;
                            case DialogResult.Cancel:
                                e.Cancel = true;
                                break;
                        }

                        if (memory)
                        {
                            _settings.SettingsFormClosingBehavior = always;
                            _settings.Save();
                        }
                        break;
                    default:
                        notifyIcon1.Visible = false;
                        break;
                }
            }
            else
                notifyIcon1.Visible = false;
        }

        /// <summary>通知アイコンに最小化します。</summary>
        protected virtual void MinimizeToNotifier()
        {
            if (DesignMode)
                return;
            if (_settings.SettingsMinimizeToNotifier && WindowState == FormWindowState.Minimized)
            {
                //フォームを非表示にする
                Visible = false;
            }
        }
        #endregion
    }
}